package zh;


import java.awt.geom.Point2D;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import robocode.*;
import zh.logging.MyLogger;


/**
 * MyFirstRobot - a sample robot by Mathew Nelson
 *
 * Moves in a seesaw motion, and spins the gun around at each end
 */
public class TargetPractice extends AdvancedRobot
{
    public boolean startGameProceduresExecuted;
    private List<Point2D> WAYPOINTLIST;
    private Point2D currentWayPoint;
    private boolean NORMAL_DIRECTION = true;
    private double WIDTH;
    private double HEIGHT;
    private double ROBOT_WIDTH_PADDING;
    private double ROBOT_HEIGHT_PADDING;
    /**
     * MyFirstRobot's run method - Seesaw
     */
    public void run()
    {
        this.setAdjustGunForRobotTurn(true);
        WIDTH = this.getBattleFieldWidth();
        HEIGHT = this.getBattleFieldHeight();
        ROBOT_WIDTH_PADDING = this.getWidth() * 1.25D;
        ROBOT_HEIGHT_PADDING = this.getHeight() * 1.25D;
        List<Point2D> temp = new ArrayList<Point2D>();/*
        temp.add(new Point2D.Double(WIDTH - ROBOT_WIDTH_PADDING, HEIGHT/2.0));
        temp.add(new Point2D.Double(ROBOT_WIDTH_PADDING, HEIGHT/2.0));*/
            temp.add(new Point2D.Double((WIDTH/3)*1, HEIGHT - ROBOT_HEIGHT_PADDING));
            temp.add(new Point2D.Double(WIDTH/2.0, HEIGHT - (ROBOT_HEIGHT_PADDING * 2)));
            temp.add(new Point2D.Double((WIDTH/3)*2, HEIGHT - (ROBOT_HEIGHT_PADDING * 1.5)));
            temp.add(new Point2D.Double(WIDTH - ROBOT_WIDTH_PADDING, HEIGHT/2.0));
            temp.add(new Point2D.Double((WIDTH/3)*2, (ROBOT_HEIGHT_PADDING * 2)));
            temp.add(new Point2D.Double(WIDTH/2.0, ROBOT_HEIGHT_PADDING));
            temp.add(new Point2D.Double((WIDTH/3)*1, (ROBOT_HEIGHT_PADDING * 1.5)));
            temp.add(new Point2D.Double(ROBOT_WIDTH_PADDING, HEIGHT/2.0));
        WAYPOINTLIST = Collections.unmodifiableList(temp);
        currentWayPoint = getClosestWayPoint();
        determineHeadingChangeToGoToPoint(currentWayPoint);
   //     setTurnRight(360.0 - this.getHeading());
        execute();/*
        double radius = WAYPOINTLIST.get(0).distance(WAYPOINTLIST.get(1))/2.0;
        this.setAhead(radius * Math.PI);
        double angle = (getX() >= WIDTH / 2.0 ? -180.0 : 180.0 );
        this.setTurnRight(angle);*/
        while (true)
        {
            if (this.getDistanceRemaining() == 0.0)
            {
                currentWayPoint = getNextWayPoint();
                determineHeadingChangeToGoToPoint(currentWayPoint);
            }
            this.setTurnRadarRight(33.3);
            this.execute();
        }
    }
    
    private Point2D getClosestWayPoint()
    {
        Point2D nextWayPoint = null;
        for (Point2D wayPoint : WAYPOINTLIST)
        {
            if (nextWayPoint == null || this.getLocation().distance(wayPoint) < this.getLocation().distance(nextWayPoint))
            {
                nextWayPoint = wayPoint;
            }
        }
        return nextWayPoint;
    }
    
    private Point2D getNextWayPoint()
    {
        List<Point2D> TMP = new ArrayList<Point2D>(WAYPOINTLIST);
        if (!NORMAL_DIRECTION)
        {
            Collections.reverse(TMP);
        }
        Point2D nextWayPoint = null;
        if (currentWayPoint == null || TMP.get(TMP.size()-1).equals(currentWayPoint))
        {
            nextWayPoint = TMP.get(0);
        }
        else
        {
            boolean foundCurrent = false;
            for (Point2D wayPoint : TMP)
            {
                if (wayPoint.equals(currentWayPoint))
                {
                    foundCurrent = true;
                }
                else if (foundCurrent)
                {
                    nextWayPoint = wayPoint;
                    break;
                }
            }
        }
//        System.out.println("nextWayPoint: " + nextWayPoint);
        return nextWayPoint;
    }
    
    
    private void determineHeadingChangeToGoToPoint(Point2D destination)
    {
        double distance = getDistanceToPointFromCurrent(destination);
        double angle = normalRelativeAngle(absoluteBearing(destination) - this.getHeading());
        if (Math.abs(angle) > 90) 
        {
            distance *= -1;
            if (angle > 0) 
            {
                angle -= 180;
            }
            else 
            {
                angle += 180;
            }
        }
//        System.out.println("distance: " + distance);
        this.setTurnRight(angle);
        this.setAhead(distance);
        this.setTurnRight(90.0);
    }
    
    private double absoluteBearing(Point2D target)
    {
        return Math.toDegrees(Math.atan2(target.getX() - this.getX(), target.getY() - this.getY()));
    }
    private double normalRelativeAngle(double angle)
    {
        angle = Math.toRadians(angle);
        return Math.toDegrees(Math.atan2(Math.sin(angle), Math.cos(angle)));
    }
    private double getDistanceToPointFromCurrent(Point2D otherPoint)
    {
        return Point2D.distance(this.getX(), this.getY(), otherPoint.getX(), otherPoint.getY());
    }
    public boolean doOtherOpponentsExist()
    {
        return (0 < getOthers());
    }
    public Point2D getLocation()
    {
        return new Point2D.Double(getX(), getY());
    }
    
    public void onHitRobot(HitRobotEvent event)
    {
        
//        robot.setStop(true);
        // Take Evasive Manuevor to evade being hit again...
        this.setTurnLeft(90 - event.getBearing());
        this.setAhead(200);
        // reverse the waypoint dirction
        NORMAL_DIRECTION = !NORMAL_DIRECTION;
        this.execute();
    }
}
